package com.mcr.reggie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mcr.reggie.dao.*;
import com.mcr.reggie.dto.DishDto;
import com.mcr.reggie.entity.*;
import com.mcr.reggie.service.DishFlavorService;
import com.mcr.reggie.service.DishService;
import com.mcr.reggie.utils.DelImage;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
    @Autowired
    private DishFlavorService dishFlavorService;
    @Autowired
    private DishFlavorMapper dishFlavorMapper;
    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private SetmealMapper setmealMapper;
    @Autowired
    private SetmealDishMapper setmealDishMapper;
    @Autowired
    private DelImage delImage;

    @Override
    @Transactional
    @CacheEvict(value = "dishCache",key = "#dishDto.getCategoryId()+'_'+#dishDto.getStatus()")
    public void saveDishAndFlavor(DishDto dishDto) {
        dishMapper.insert(dishDto);
        Long dishId = dishDto.getId();
        List<DishFlavor> flavors = dishDto.getFlavors();
        flavors=flavors.stream().map((item)->{
            item.setDishId(dishId);
            return item;
        }).collect(Collectors.toList());
        dishFlavorService.saveBatch(flavors);
    }
    @Override
    public Page<DishDto> getPage(int page, int pageSize, String name) {
        Page<Dish> dishPage=new Page<>(page,pageSize);
        Page<DishDto> dishDtoPage=new Page<>();
        LambdaQueryWrapper<Dish> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.like((name!=null),Dish::getName,name);
        queryWrapper.orderByDesc(Dish::getUpdateTime);
        dishMapper.selectPage(dishPage,queryWrapper);
        if(dishPage.getRecords().size()==0){
            return null;
        }
        //对象拷贝(第3个参数:忽略records属性)
        BeanUtils.copyProperties(dishPage,dishDtoPage,"records");
        List<Dish> dishList = dishPage.getRecords();
        List<DishDto> dishDtoList=dishDtoBOS_NoFlavor(dishList);
        dishDtoPage.setRecords(dishDtoList);
        return dishDtoPage;
    }
    @Override
    public DishDto getDishAndFlavor(Long id) {
        DishDto dishDto=new DishDto();
        //dish表查询菜品基本信息
        Dish dish = dishMapper.selectById(id);
        BeanUtils.copyProperties(dish,dishDto);
        //dish_flavor表查询从菜品口味信息
        LambdaQueryWrapper<DishFlavor> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(DishFlavor::getDishId,id);
        List<DishFlavor> flavors= dishFlavorMapper.selectList(queryWrapper);
        dishDto.setFlavors(flavors);
        return dishDto;
    }
    @Override
    @Transactional
    @CacheEvict(value = "dishCache",allEntries = true)
    public void updateDishAndFlavor(DishDto dishDto) {
        //更新dish表基本信息
        dishMapper.updateById(dishDto);
        //清理当前菜品对应口味数据
        LambdaQueryWrapper<DishFlavor> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(DishFlavor::getDishId, dishDto.getId());
        dishFlavorMapper.delete(queryWrapper);
        //添加当前提交过来的口味数据
        if(dishDto.getFlavors().size()==0){//没有口味数据则直接结束
            return;
        }
        List<DishFlavor> flavors = new ArrayList<>();
        Map<String,DishFlavor> dishFlavorMap=new HashMap<>();//key:菜品口味名,value:菜品口味对象
        for(DishFlavor df:dishDto.getFlavors()){
            if(null==dishFlavorMap.get(df.getName())){
                df.setDishId(dishDto.getId());
                dishFlavorMap.put(df.getName(),df);
            }
        }
        for(DishFlavor df:dishFlavorMap.values()){
            flavors.add(df);
        }
        dishFlavorService.saveBatch(flavors);
    }
    @Override
    @Transactional//修改菜品状态
    //菜品的启停售可能会影响到套餐的其停售，所以清除所有cache
    @Caching(evict = {
            @CacheEvict(value = "dishCache",allEntries = true),
            @CacheEvict(value = "setmealCache",allEntries = true)
    })
    public void updateDishStatus(Long[] ids, Integer status) {
        LambdaUpdateWrapper<Dish> dishUpdateWrapper=new LambdaUpdateWrapper<>();
        dishUpdateWrapper.in(Dish::getId,ids);
        Dish dish=new Dish();
        dish.setStatus(status);
        dishMapper.update(dish,dishUpdateWrapper);//sql-1
        if(status==0){//停售状态的话相应套餐也要停售
            Setmeal setmeal=new Setmeal();
            setmeal.setStatus(0);
            LambdaQueryWrapper<SetmealDish> setmealDishQueryWrapper=new LambdaQueryWrapper<>();
            setmealDishQueryWrapper.in(SetmealDish::getDishId,ids);
            List<SetmealDish> setmealDishes = setmealDishMapper.selectList(setmealDishQueryWrapper);//sql-2
            if(setmealDishes.size()==0){
                return;
            }
            Long[] setmealIds=new Long[setmealDishes.size()];
            for(int i=0;i<setmealIds.length;i++){
                setmealIds[i]=setmealDishes.get(i).getSetmealId();//得到所有与此停售菜品相关的套餐id数据
            }
            LambdaUpdateWrapper<Setmeal> setmealUpdateWrapper=new LambdaUpdateWrapper<>();
            setmealUpdateWrapper.in(Setmeal::getId,setmealIds);
            setmealMapper.update(setmeal,setmealUpdateWrapper);//sql-3
        }
    }
    @Override
    @Transactional
    //菜品的启停售可能会影响到套餐的其停售，所以清除所有cache
    @Caching(evict = {
            @CacheEvict(value = "dishCache",allEntries = true),
            @CacheEvict(value = "setmealCache",allEntries = true)
    })
    public void delByIds(Long[] ids) {
        //首先删除这些菜品
        LambdaUpdateWrapper<Dish> dishUpdateWrapper=new LambdaUpdateWrapper<>();
        dishUpdateWrapper.in(Dish::getId,ids);
        List<Dish> delDishImgs = dishMapper.selectList(dishUpdateWrapper);
        //先查出要删除数据的信息，用于最后删菜品图片
        dishMapper.delete(dishUpdateWrapper);//再删除dish数据
        //查询有没有和这些菜品关联的套餐
        LambdaQueryWrapper<SetmealDish> setmealDishQueryWrapper=new LambdaQueryWrapper<>();
        setmealDishQueryWrapper.in(SetmealDish::getDishId,ids);
        List<SetmealDish> setmealDishes = setmealDishMapper.selectList(setmealDishQueryWrapper);
        if(setmealDishes.size()==0){//最后再把菜品图片删除
            for(Dish dish:delDishImgs){
                delImage.delImage(dish.getImage());
            }
            return;//没有直接返回
        }//有的话把这些套餐也给删除了
        Long[] setmealIds=new Long[setmealDishes.size()];
        for(int i=0;i<setmealIds.length;i++){
            setmealIds[i]=setmealDishes.get(i).getSetmealId();//得到所有与此停售菜品相关的套餐id数据
        }
        //把与这些菜品关联的套餐删除
        LambdaUpdateWrapper<Setmeal> setmealUpdateWrapper=new LambdaUpdateWrapper<>();
        setmealUpdateWrapper.in(Setmeal::getId,setmealIds);
        setmealMapper.delete(setmealUpdateWrapper);
        //把与这些菜品关联的口味表数据也删了
        setmealDishMapper.delete(setmealDishQueryWrapper);
        //最后再把菜品图片删除
        for(Dish dish:delDishImgs){
            delImage.delImage(dish.getImage());
        }
    }
    @Override
    @Cacheable(value = "dishCache",key = "#dish.getCategoryId()+'_'+#dish.getStatus()",condition = "#dish.getStatus()==1")
    public List<DishDto> getList(Dish dish) {
        LambdaQueryWrapper<Dish> dishQueryWrapper=new LambdaQueryWrapper<>();
        //先查询Dish
        dishQueryWrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());
        dishQueryWrapper.like(dish.getName()!=null,Dish::getName,dish.getName());
        dishQueryWrapper.eq(dish.getStatus()!=null,Dish::getStatus,dish.getStatus());
        dishQueryWrapper.orderByAsc(Dish::getSort).orderByAsc(Dish::getUpdateTime);
        List<Dish> dishList= dishMapper.selectList(dishQueryWrapper);
        if(dish.getStatus()==null){
            return dishList.stream().map((dishl)->{
                DishDto dishDto=new DishDto();
                BeanUtils.copyProperties(dishl,dishDto);
                return dishDto;
            }).collect(Collectors.toList());
        }
        List<DishDto> dishDtoList=this.dishDtoBOS_NoCategoryName(dishList);
        return dishDtoList;
    }
    //实体类转换工具方法(不要口味信息),Dish--->DishDto
    private List<DishDto> dishDtoBOS_NoFlavor(List<Dish> dishes){
        List<Long> categoryIds=new ArrayList<>(dishes.size());
        for(Dish dish:dishes){
            categoryIds.add(dish.getCategoryId());
        }
        List<Category> categories = categoryMapper.selectBatchIds(categoryIds);
        Map<Long,String> categoryNameMap=new HashMap<Long,String>();
        for(Category category:categories){
            categoryNameMap.put(category.getId(),category.getName());
        }
        List<DishDto> dishDtoList=dishes.stream().map((dish) -> {
            DishDto dishDto=new DishDto();
            BeanUtils.copyProperties(dish,dishDto);
            dishDto.setCategoryName(categoryNameMap.get(dish.getCategoryId()));
            return dishDto;
        }).collect(Collectors.toList());
        return dishDtoList;
    }
    //实体类转换工具方法(不要分类名称),Dish--->DishDto
    private List<DishDto> dishDtoBOS_NoCategoryName(List<Dish> dishes){
        List<Long> dishIds=new ArrayList<>(dishes.size());
        Map<Long,List<DishFlavor>> dishFlavorMap=new HashMap<>();
        for(Dish dish:dishes){
            dishIds.add(dish.getId());
            dishFlavorMap.put(dish.getId(),new ArrayList<>());
        }
        LambdaQueryWrapper<DishFlavor> dishFlavorQueryWrapper=new LambdaQueryWrapper<>();
        dishFlavorQueryWrapper.in(DishFlavor::getDishId,dishIds);
        List<DishFlavor> flavors = dishFlavorMapper.selectList(dishFlavorQueryWrapper);
        for(DishFlavor dishFlavor:flavors){
            dishFlavorMap.get(dishFlavor.getDishId()).add(dishFlavor);
        }
        List<DishDto> dishDtos=dishes.stream().map((dish)->{
            DishDto dishDto=new DishDto();
            BeanUtils.copyProperties(dish,dishDto);
            dishDto.setFlavors(dishFlavorMap.get(dish.getId()));
            return dishDto;
        }).collect(Collectors.toList());
        return dishDtos;
    }
}